package com.ruoyi.factorydata.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.CacheSupportUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.factorydata.domain.*;
import com.ruoyi.factorydata.mapper.*;
import com.ruoyi.factorydata.service.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;

/**
 * 物料库存信息Service业务层处理
 *
 * @author ruoyi
 * @date 2025-07-23
 */
@Service
public class MaterialInventoryServiceImpl extends ServiceImpl<MaterialInventoryMapper, MaterialInventory> implements IMaterialInventoryService {
    private final MaterialInventoryMapper materialInventoryMapper;
    private final MaterialInventoryFlowMapper materialInventoryFlowMapper;
    private final MaterialDataMapper materialDataMapper;
    private final IMaterialUnitDataService materialUnitDataService;
    private final IWarehouseInfoService warehouseInfoService;
    private final IWarehousePositionService warehousePositionService;
    private final IMaterialCategoryService materialCategoryService;
    private final IWorkOrderInfoService workOrderInfoService;
    private final InventoryReceiptInfoMapper inventoryReceiptInfoMapper;
    private final InventoryReceiptDetailMapper inventoryReceiptDetailMapper;
    private final CustomerDataMapper customerDataMapper;

    public MaterialInventoryServiceImpl(MaterialInventoryMapper materialInventoryMapper,
                                        MaterialInventoryFlowMapper materialInventoryFlowMapper,
                                        MaterialDataMapper materialDataMapper,
                                        IMaterialUnitDataService materialUnitDataService,
                                        IWarehouseInfoService warehouseInfoService,
                                        IWarehousePositionService warehousePositionService,
                                        IMaterialCategoryService materialCategoryService,
                                        IWorkOrderInfoService workOrderInfoService,
                                        InventoryReceiptInfoMapper inventoryReceiptInfoMapper,
                                        InventoryReceiptDetailMapper inventoryReceiptDetailMapper,
                                        CustomerDataMapper customerDataMapper) {
        this.materialInventoryMapper = materialInventoryMapper;
        this.materialInventoryFlowMapper = materialInventoryFlowMapper;
        this.materialDataMapper = materialDataMapper;
        this.materialUnitDataService = materialUnitDataService;
        this.warehouseInfoService = warehouseInfoService;
        this.warehousePositionService = warehousePositionService;
        this.materialCategoryService = materialCategoryService;
        this.workOrderInfoService = workOrderInfoService;
        this.inventoryReceiptInfoMapper = inventoryReceiptInfoMapper;
        this.inventoryReceiptDetailMapper = inventoryReceiptDetailMapper;
        this.customerDataMapper = customerDataMapper;
    }

    /**
     * 查询物料库存信息
     *
     * @param id 物料库存信息主键
     * @return 物料库存信息
     */
    @Override
    public MaterialInventory selectMaterialInventoryById(Long id) {
        return materialInventoryMapper.selectMaterialInventoryById(id);
    }

    /**
     * 查询物料库存信息列表
     *
     * @param materialInventory 物料库存信息
     * @return 物料库存信息
     */
    @Override
    public List<MaterialInventory> selectMaterialInventoryList(MaterialInventory materialInventory) {
        List<MaterialInventory> materialInventories = materialInventoryMapper.selectMaterialInventoryList(materialInventory);

        HashMap<Long, String> unitNameCache = new HashMap<>();
        HashMap<Long, String> positionNameCache = new HashMap<>();
        HashMap<Long, String> warehouseNameCache = new HashMap<>();
        HashMap<Long, String> categoryNameCache = new HashMap<>();
        HashMap<Long, MaterialData> materialDataCache = new HashMap<>();
        HashMap<Long, String> customCodeCache = new HashMap<>();

        materialInventories.forEach(inventory -> {
            String unitName = materialUnitDataService.getByIdAndCache(inventory.getMaterialUnit(), unitNameCache);
            String positionName = warehousePositionService.getByIdAndCache(inventory.getWarehousePositionId(), positionNameCache);
            String warehouseName = warehouseInfoService.getNameByIdAndCache(inventory.getWarehouseId(), warehouseNameCache);
            String categoryName = materialCategoryService.getNameByIdAndCache(inventory.getMaterialCategory(), categoryNameCache);
            MaterialData materialData = CacheSupportUtils.getFromCacheOrDB(inventory.getMaterialId(), materialDataCache,materialDataMapper::selectMaterialDataById, materialData1 -> materialData1,false);
            String customCode = null;
            if(materialData!=null){
                customCode=CacheSupportUtils.getFromCacheOrDB(materialData.getCustomerId(), customCodeCache, customerDataMapper::selectCustomerDataById, CustomerData::getCustomerCode, false);
            }
            inventory.setMaterialUnitName(unitName);
            inventory.setWarehousePositionName(positionName);
            inventory.setWarehouseName(warehouseName);
            inventory.setMaterialCategoryName(categoryName);
            inventory.setCustomerId(Optional.ofNullable(materialData).orElse(new MaterialData()).getCustomerId());
            inventory.setCustomerCode(customCode);
            inventory.setRemark(Optional.ofNullable(materialData).map(MaterialData::getRemark).orElse( null));
            //计算库龄，入库时间到现在有多少天了
            int stockAge = DateUtils.differentDaysByMillisecond(inventory.getReceiptDate(), DateUtils.getNowDate());
            inventory.setStockAge(stockAge);
        });
        return materialInventories;
    }

    /**
     * 新增物料库存信息
     *
     * @param materialInventory 物料库存信息
     * @return 结果
     */
    @Override
    public int insertMaterialInventory(MaterialInventory materialInventory) {
                materialInventory.setCreateTime(DateUtils.getNowDate());
            return materialInventoryMapper.insertMaterialInventory(materialInventory);
    }

    /**
     * 修改物料库存信息
     *
     * @param materialInventory 物料库存信息
     * @return 结果
     */
    @Override
    public int updateMaterialInventory(MaterialInventory materialInventory) {
                materialInventory.setUpdateTime(DateUtils.getNowDate());
        return materialInventoryMapper.updateMaterialInventory(materialInventory);
    }

    /**
     * 批量删除物料库存信息
     *
     * @param ids 需要删除的物料库存信息主键
     * @return 结果
     */
    @Override
    public int deleteMaterialInventoryByIds(Long[] ids) {
        return materialInventoryMapper.deleteMaterialInventoryByIds(ids);
    }

    /**
     * 删除物料库存信息信息
     *
     * @param id 物料库存信息主键
     * @return 结果
     */
    @Override
    public int deleteMaterialInventoryById(Long id) {
        return materialInventoryMapper.deleteMaterialInventoryById(id);
    }

    @Override
    @Transactional
    public void saveInventoryIn(InventoryReceiptInfo inventoryReceiptInfo, InventoryReceiptDetail inventoryReceiptDetail, String batchNumber) {
        MaterialData materialData = materialDataMapper.selectById(inventoryReceiptDetail.getMaterialId());
        Assert.notNull(materialData, "物料编码:"+inventoryReceiptDetail.getMaterialCode()+"不存在");
        MaterialInventory materialInventory = MaterialInventory.builder()
                .batchNumber(batchNumber)
                .warehouseId(inventoryReceiptDetail.getWarehouseId())
                .warehouseCode(inventoryReceiptDetail.getWarehouseCode())
                .warehousePositionId(inventoryReceiptDetail.getWarehousePositionId())
                .warehousePositionCode(inventoryReceiptDetail.getWarehousePositionCode())
                .materialId(inventoryReceiptDetail.getMaterialId())
                .materialCode(inventoryReceiptDetail.getMaterialCode())
                .materialName(inventoryReceiptDetail.getMaterialName())
                .materialSpecification(inventoryReceiptDetail.getMaterialSpecification())
                .manufacturingMethod(materialData.getManufacturingMethod())
                .materialUnit(materialData.getMaterialUnit())
                .materialType(materialData.getMaterialType())
                .materialCategory(materialData.getCategoryId())
                .stockQuantity(inventoryReceiptDetail.getActualQuantity())
                .receiptDate(inventoryReceiptInfo.getReceiptDate())
                .build();
        materialInventory.setCreateBy(inventoryReceiptInfo.getCreateBy());
        int insert = materialInventoryMapper.insertMaterialInventory(materialInventory);
        Assert.isTrue(insert > 0, "入库失败");
        //添加入库单明细
        MaterialInventoryFlow inventoryFlow = MaterialInventoryFlow.builder()
                .documentNumber(inventoryReceiptInfo.getReceiptType()==1?inventoryReceiptInfo.getPurchaseOrderCode():inventoryReceiptInfo.getWorkOrderCode())
                .flowType("in")//采购入库
                .documentType(inventoryReceiptInfo.getReceiptType()==1?"purchase":"product_in")
                .warehouseId(inventoryReceiptDetail.getWarehouseId())
                .warehouseCode(inventoryReceiptDetail.getWarehouseCode())
                .warehousePositionId(inventoryReceiptDetail.getWarehousePositionId())
                .warehousePositionCode(inventoryReceiptDetail.getWarehousePositionCode())
                .materialId(inventoryReceiptDetail.getMaterialId())
                .materialCode(inventoryReceiptDetail.getMaterialCode())
                .materialName(inventoryReceiptDetail.getMaterialName())
                .materialCategory(materialInventory.getMaterialCategory())
                .materialType(materialInventory.getMaterialType())
                .materialUnit(materialInventory.getMaterialUnit())
                .quantity(inventoryReceiptDetail.getActualQuantity())
                .batchNumber(batchNumber)
                .build();
        inventoryFlow.setCreateBy(inventoryReceiptInfo.getCreateBy());
        inventoryFlow.setRemark(inventoryReceiptInfo.getRemark());
        insert = materialInventoryFlowMapper.insertMaterialInventoryFlow(inventoryFlow);
        Assert.isTrue(insert > 0, "入库失败");
    }

    @Override
    public Long countMaterialInventoryList(MaterialInventory materialInventory) {
        return materialInventoryMapper.countMaterialInventoryList(materialInventory);
    }

    @Override
    public void saveInventoryOut(MaterialRequisitionDetail materialRequisitionDetail, String inventoryBatchNumber, BigDecimal inventoryQuantity) {
        MaterialInventory inventory = lambdaQuery()
                .eq(MaterialInventory::getBatchNumber, inventoryBatchNumber)
                .eq(MaterialInventory::getMaterialCode, materialRequisitionDetail.getMaterialCode())
                .last("limit 1")
                .one();
        Assert.notNull(inventory, "批次:"+inventoryBatchNumber+"不存在");
        Assert.isTrue(new BigDecimal(inventory.getStockQuantity()).compareTo(inventoryQuantity) >= 0, "库存数量不足");
        inventory.setUpdateBy(SecurityUtils.getUserId() + "");
        inventory.setUpdateTime(DateUtils.getNowDate());
        inventory.setStockQuantity(inventory.getStockQuantity() - inventoryQuantity.intValue());
        int update = materialInventoryMapper.updateMaterialInventory(inventory);
        Assert.isTrue(update > 0, "出库失败");
        //添加入库单明细
        MaterialInventoryFlow inventoryFlow = MaterialInventoryFlow.builder()
                .documentNumber(materialRequisitionDetail.getRequisitionNo())
                .flowType("out")//领料单出库
                .documentType("requisitionOut")
                .warehouseId(inventory.getWarehouseId())
                .warehouseCode(inventory.getWarehouseCode())
                .warehousePositionId(inventory.getWarehousePositionId())
                .warehousePositionCode(inventory.getWarehousePositionCode())
                .materialId(inventory.getMaterialId())
                .materialCode(inventory.getMaterialCode())
                .materialName(inventory.getMaterialName())
                .materialCategory(inventory.getMaterialCategory())
                .materialType(inventory.getMaterialType())
                .materialUnit(inventory.getMaterialUnit())
                .quantity(inventoryQuantity.longValue())
                .batchNumber(inventoryBatchNumber)
                .build();
        inventoryFlow.setCreateBy(SecurityUtils.getUserId() + "");
        inventoryFlow.setRemark(materialRequisitionDetail.getRemark());
        int insert = materialInventoryFlowMapper.insertMaterialInventoryFlow(inventoryFlow);
        Assert.isTrue(insert > 0, "出库流水记录失败");
    }

    @Override
    public void saveInventoryIn(MaterialRequisitionDetail materialRequisitionDetail, String inventoryBatchNumber, BigDecimal inventoryQuantity) {
        MaterialInventory inventory = lambdaQuery()
                .eq(MaterialInventory::getBatchNumber, inventoryBatchNumber)
                .eq(MaterialInventory::getMaterialId, materialRequisitionDetail.getMaterialId())
                .last("limit 1")
                .one();
        Assert.notNull(inventory, "批次:"+inventoryBatchNumber+"不存在");
        inventory.setUpdateBy(SecurityUtils.getUserId() + "");
        inventory.setUpdateTime(DateUtils.getNowDate());
        inventory.setStockQuantity(inventory.getStockQuantity() + inventoryQuantity.intValue());
        int update = materialInventoryMapper.updateMaterialInventory(inventory);
        Assert.isTrue(update > 0, "出库失败");
        //添加入库单明细
        MaterialInventoryFlow inventoryFlow = MaterialInventoryFlow.builder()
                .documentNumber(materialRequisitionDetail.getRequisitionNo())
                .flowType("in")//领料单退料入库库
                .documentType("requisition_return_in")
                .warehouseId(inventory.getWarehouseId())
                .warehouseCode(inventory.getWarehouseCode())
                .warehousePositionId(inventory.getWarehousePositionId())
                .warehousePositionCode(inventory.getWarehousePositionCode())
                .materialId(inventory.getMaterialId())
                .materialCode(inventory.getMaterialCode())
                .materialName(inventory.getMaterialName())
                .materialCategory(inventory.getMaterialCategory())
                .materialType(inventory.getMaterialType())
                .materialUnit(inventory.getMaterialUnit())
                .quantity(inventoryQuantity.longValue())
                .batchNumber(inventoryBatchNumber)
                .build();
        inventoryFlow.setCreateBy(SecurityUtils.getUserId() + "");
        inventoryFlow.setRemark(materialRequisitionDetail.getRemark());
        int insert = materialInventoryFlowMapper.insertMaterialInventoryFlow(inventoryFlow);
        Assert.isTrue(insert > 0, "出库流水记录失败");
    }

    @Override
    public void saveInventoryOut(StockOutOrderDetail stockOutOrderDetail, String inventoryBatchNumber, BigDecimal inventoryQuantity) {
        MaterialInventory inventory = lambdaQuery()
                .eq(MaterialInventory::getBatchNumber, inventoryBatchNumber)
                .eq(MaterialInventory::getMaterialCode, stockOutOrderDetail.getMaterialCode())
                .last("limit 1")
                .one();
        Assert.notNull(inventory, "批次:"+inventoryBatchNumber+"不存在");
        Assert.isTrue(new BigDecimal(inventory.getStockQuantity()).compareTo(inventoryQuantity) >= 0, "库存数量不足");
        inventory.setUpdateBy(SecurityUtils.getUserId() + "");
        inventory.setUpdateTime(DateUtils.getNowDate());
        inventory.setStockQuantity(inventory.getStockQuantity() - inventoryQuantity.intValue());
        int update = materialInventoryMapper.updateMaterialInventory(inventory);
        Assert.isTrue(update > 0, "出库失败");
        //添加入库单明细
        MaterialInventoryFlow inventoryFlow = MaterialInventoryFlow.builder()
                .documentNumber(stockOutOrderDetail.getOrderNo())
                .flowType("out")//出库单出库
                .documentType("stock_out")
                .warehouseId(inventory.getWarehouseId())
                .warehouseCode(inventory.getWarehouseCode())
                .warehousePositionId(inventory.getWarehousePositionId())
                .warehousePositionCode(inventory.getWarehousePositionCode())
                .materialId(inventory.getMaterialId())
                .materialCode(inventory.getMaterialCode())
                .materialName(inventory.getMaterialName())
                .materialCategory(inventory.getMaterialCategory())
                .materialType(inventory.getMaterialType())
                .materialUnit(inventory.getMaterialUnit())
                .quantity(inventoryQuantity.longValue())
                .batchNumber(inventoryBatchNumber)
                .build();
        inventoryFlow.setCreateBy(SecurityUtils.getUserId() + "");
        inventoryFlow.setRemark(stockOutOrderDetail.getRemark());
        int insert = materialInventoryFlowMapper.insertMaterialInventoryFlow(inventoryFlow);
        Assert.isTrue(insert > 0, "出库流水记录失败");
    }

    @Override
    public MaterialInventory getScannerInfo(Long inventoryReceiptId) {
        Assert.notNull(inventoryReceiptId, "参数不能为空");
        InventoryReceiptInfo receiptInfo = inventoryReceiptInfoMapper.selectInventoryReceiptInfoById(inventoryReceiptId);
        Assert.notNull(receiptInfo, "数据不存在");
        List<InventoryReceiptDetail> inventoryReceiptDetails = inventoryReceiptDetailMapper.selectInventoryReceiptDetailList(InventoryReceiptDetail.builder().receiptId(inventoryReceiptId).build());
        Assert.notNull(inventoryReceiptDetails!=null&&inventoryReceiptDetails.size()>0, "数据不存在");
        InventoryReceiptDetail inventoryReceiptDetail = inventoryReceiptDetails.get(0);
        MaterialInventory materialInventory = materialInventoryMapper.selectByWorkOrder(receiptInfo.getWorkOrderCode());
        Assert.notNull(materialInventory, "数据不存在");
        MaterialData materialData = materialDataMapper.selectMaterialDataById(materialInventory.getMaterialId());
        //获取关联工单
        List<WorkOrderInfo> workOrderInfos = workOrderInfoService.selectWorkOrderInfoList(WorkOrderInfo.builder().workOrderCode(receiptInfo.getWorkOrderCode()).build());
        materialInventory.setWorkOrderInfoList(workOrderInfos);
        String unitName = materialUnitDataService.getByIdAndCache(materialInventory.getMaterialUnit(), new HashMap<>());
        String positionName = warehousePositionService.getByIdAndCache(materialInventory.getWarehousePositionId(),  new HashMap<>());
        String warehouseName = warehouseInfoService.getNameByIdAndCache(materialInventory.getWarehouseId(),  new HashMap<>());
        String categoryName = materialCategoryService.getNameByIdAndCache(materialInventory.getMaterialCategory(),  new HashMap<>());
        materialInventory.setWarehouseName(warehouseName);
        materialInventory.setWarehousePositionName(positionName);
        materialInventory.setMaterialUnitName(unitName);
        materialInventory.setMaterialCategoryName(categoryName);
        if(materialData!=null){
            materialInventory.setMaterialImages(materialData.getMaterialImages());
            String customCode=CacheSupportUtils.getFromCacheOrDB(materialData.getCustomerId(), new HashMap<>(), customerDataMapper::selectCustomerDataById, CustomerData::getCustomerCode,false);
            materialInventory.setCustomerId(materialData.getCustomerId());
            materialInventory.setCustomerCode(customCode);
        }
        materialInventory.setProductionDate(inventoryReceiptDetail.getProductionDate());
        return materialInventory;
    }
}